package cn.ulyer.generator.service;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.ulyer.common.model.PageableVo;
import cn.ulyer.common.utils.PageResult;
import cn.ulyer.common.utils.PageUtil;
import cn.ulyer.generator.model.GeneratorModel;
import cn.ulyer.generator.util.JdbcTypeUtil;
import cn.ulyer.generator.util.VelocityUtil;
import cn.ulyer.generator.vo.ColumnVo;
import cn.ulyer.generator.vo.TableVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.VelocityContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

@Service
@Slf4j
public class GeneratorService {

    String TABLE_QUERY = "select table_name as name,table_comment as comment,create_time as createTime,engine ,table_collation as encode  from information_schema.TABLES WHERE  table_schema =(SELECT database())";

    String COLUMN_QUERY = "select column_type as columnDefinition,table_name as tableName,column_name as name,data_type as jdbcType,column_key as columnKey,is_nullable as isNullable ,column_comment as comment " +
            "from information_schema.COLUMNS WHERE table_name = ? AND table_schema =(SELECT database())";


    /**
     * 分页查表
     * @param dataSource
     * @param pageableVo
     * @param tableName
     * @return
     */
    public PageResult<TableVo> queryTables(DataSource dataSource, PageableVo pageableVo, String tableName){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        String query = TABLE_QUERY;
        List<Object> params  = new LinkedList<>();
        if(StrUtil.isNotBlank(tableName)){
            query += " and table_name = ?";
            params.add(tableName);
        }
        String countSql = PageUtil.countSql(query);
        Integer count = jdbcTemplate.queryForObject(countSql,Integer.class,params.toArray());
        PageResult<TableVo> pageResult = new PageResult<>();
        pageResult.setTotal(count);
        pageResult.setSize(pageableVo.getSize());
        pageResult.setPages(PageUtil.totalPage(count,pageResult.getSize()));
        String pageSql = PageUtil.pageSql(query,pageableVo);
        if(count!=0){
            List<TableVo> data = jdbcTemplate.query(pageSql,new BeanPropertyRowMapper<>(TableVo.class),params.toArray());
            pageResult.setRecords(data);
        }
        return pageResult;
    }


    /**
     * 把字段查出来 生成
     * @param generatorModel
     * @param dataSource
     * @param basePath
     *
     * entityName,package,idType,idName,module,tableName,columns
     *
     * @return true  when empty columns or success
     */
    public boolean generator(GeneratorModel generatorModel, DataSource dataSource, String basePath,String theme){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        List<String> tables = generatorModel.getTableNames();
        if(tables == null){
            return true;
        }
        Set<String> created = new HashSet<>();
        String packageName = generatorModel.getPackagePath();
        try {
            for (String table : tables) {
                if(created.contains(table)){
                    continue;
                }
                List<ColumnVo> columnVos = jdbcTemplate.query(COLUMN_QUERY+"order by ORDINAL_POSITION asc",new Object[]{table},new BeanPropertyRowMapper<>(ColumnVo.class));
                if(CollectionUtils.isEmpty(columnVos)){
                    continue;
                }
                String moduleName = StrUtil.toCamelCase(table);
                char first = moduleName.charAt(0);
                if(first>'Z'&&first<='z'){
                    first -= 32;
                }
                String entityName = first+moduleName.substring(1);
                VelocityContext context = new VelocityContext();
                TableVo tableVo = jdbcTemplate.queryForObject(TABLE_QUERY+" and table_name = ?",new Object[]{table},new BeanPropertyRowMapper<>(TableVo.class));
                context.put("tableInfo",tableVo);
                context.put("package",packageName);
                context.put("module",moduleName);
                context.put("entityName",entityName);
                String idName = "id";
                String idType = "Integer";
                for (ColumnVo columnVo : columnVos) {
                    String javaType = JdbcTypeUtil.getJavaTypeByJdbcType(columnVo.getJdbcType());
                    if(columnVo.isPrimaryKey()){
                        idName = columnVo.getName();
                        idType = javaType;
                    }
                    columnVo.setName(StrUtil.toCamelCase(columnVo.getName()));
                    columnVo.setJavaType(javaType);
                }
                context.put("idName",idName);
                context.put("idType",idType);
                context.put("columns",columnVos);
                context.put("tableName",table);
                created.add(table);


                generatorRestAndView(context,basePath,theme);
                generatorService(context,basePath);
                generatorRepository(context,basePath);
                generatorJavaEntity(context,basePath);
            }

        }catch (Exception e){
            log.error("generator model error :{}",e);
            return false;
        }
        return true;
    }


    private void generatorRestAndView(VelocityContext context, String basePath,String theme) throws IOException {
        File file = new File(basePath+"/controller");
        if(!file.exists()){
            file.mkdir();
        }
        File view = new File(basePath+"/view");
        if(!view.exists()){
            view.mkdir();
        }
        String controller = VelocityUtil.renderHtml(context,"templates/java/Rest.vm");
        FileUtil.writeBytes(controller.getBytes(),file.getAbsolutePath()+"/"+context.get("entityName")+"Rest.java");

        String vue = VelocityUtil.renderHtml(context, "templates/vue/"+theme+"/Vue.vm");
        FileUtil.writeBytes(vue.getBytes(),view.getAbsolutePath()+"/"+context.get("module")+".vue");

        String api = VelocityUtil.renderHtml(context,"templates/vue/Api.vm");
        FileUtil.writeBytes(api.getBytes(),view.getAbsolutePath()+"/"+context.get("module")+".js");

    }

    private void generatorService(VelocityContext context,String basePath)throws IOException{
        File serviceFolder = new File(basePath+"/service");
        if(!serviceFolder.exists()){
            serviceFolder.mkdir();
        }
        File impl = new File(serviceFolder.getAbsolutePath()+"/impl");
        if(!impl.exists()){
            impl.mkdir();
        }
        String service = VelocityUtil.renderHtml(context,"templates/java/ModelService.vm");
        FileUtil.writeBytes(service.getBytes(),serviceFolder.getAbsolutePath()+"/"+context.get("entityName")+"Service.java");

        String serviceImpl = VelocityUtil.renderHtml(context,"templates/java/ServiceImpl.vm");
        FileUtil.writeBytes(serviceImpl.getBytes(),impl.getAbsolutePath()+"/"+context.get("entityName")+"ServiceImpl.java");

    }

    private void generatorRepository(VelocityContext context,String basePath)throws IOException{
        File repositoryFolder = new File(basePath+"/repository");
        if(!repositoryFolder.exists()){
            repositoryFolder.mkdir();
        }
        String repository = VelocityUtil.renderHtml(context,"templates/java/Repository.vm");
        FileUtil.writeBytes(repository.getBytes(),repositoryFolder.getAbsolutePath()+"/"+context.get("entityName")+"Repository.java");
    }


    private void generatorJavaEntity(VelocityContext context,String basePath) throws IOException {
        File entityFolder = new File(basePath+"/entity");
        if(!entityFolder.exists()){
            entityFolder.mkdir();
        }
        String entity = VelocityUtil.renderHtml(context,"templates/java/Entity.vm");
        FileUtil.writeBytes(entity.getBytes(),entityFolder.getAbsolutePath()+"/"+context.get("entityName")+".java");
    }






}
